反向传播算法推导-全连接神经网络
广而告之
SIGAI-AI学习交流群的目标是为学习者提供一个AI技术交流与分享的平台。操作指引:关注本微信公众号,回复“芝麻开门”,即可收到入群二维码,扫码即可。
同时在本微信公众号中,回复“SIGAI”+日期,如“SIGAI0515”,即可获取本期文章的全文下载地址(仅供个人学习使用,未经允许,不得用于商业目的)。
反向传播算法是人工神经网络训练时采用的一种通用方法,在现代深度学习中得到了大规模的应用。全连接神经网络(多层感知器模型,MLP),卷积神经网络(CNN),循环神经网络(RNN)中都有它的实现版本。算法从多元复合函数求导的链式法则导出,递推的计算神经网络每一层参数的梯度值。算法名称中的“误差”是指损失函数对神经网络每一层临时输出值的梯度。反向传播算法从神经网络的输出层开始,利用递推公式根据后一层的误差计算本层的误差,通过误差计算本层参数的梯度值,然后将差项传播到前一层。
反向传播算法是一个通用的思路。全连接神经网络给出的是全连接层的反向传播实现;卷积神经网络引入了卷积层和池化层,对这两种层的反向传播做了自己的处理;循环神经网络因为在各个时刻共享了权重矩阵和偏置向量,因此需要进行特殊处理,为此出现了BPTT算法,误差项沿着时间轴反向传播。
本文推导全连接神经网络的反向传播算法。首先推导一个简单神经网络的反向传播算法,接下来把它推广到更一般的情况,得到通用的反向传播算法。很多同学对市面上已有的推导过程讲解的困惑在于不清楚矩阵和向量的求导公式和来历,在这里我们避免此问题,直接根据几个浅显易懂的基本结论进行推导。在SIGAI后续的公众号文章中,我们将会推导卷积神经网络和循环神经网络的反向传播算法,感兴趣的读者可以关注我们的公众号。
算法的历史
反向传播算法最早出现于1986年,用于解决多层神经网络的训练问题,由Rumelhart和Hinton等人提出,这篇论文当时发表在Nature上:
David E. Rumelhart, Geoffrey E. Hinton, and Ronald J. Williams. Learning internal representations by back-propagating errors. Nature, 323(99): 533-536, 1986.
要知道,计算机的论文想发到Nature和Science上是非常困难的。笔者列举了一下发到这些期刊上的一些典型文章:
Roweis, Sam T and Saul, Lawrence K. Nonlinear dimensionality reduction by locally linear embedding. Science, 290(5500). 2000: 2323-2326.
这是流形学习的开山之作。
Tenenbaum, Joshua B and De Silva, Vin and Langford, John C. A global geometric framework for nonlinear dimensionality reduction. Science, 290(5500). 2000: 2319-2323.
G.E.Hinton, et al. Reducing the Dimensionality of Data with Neural Networks, Science 313, 504,2006.
这是深度学习的开山之作。Hinton同志几十年如一日孜孜不倦的探索着神经网络,在最低谷的时候也毅然坚持,在这里我们先向他致敬!
下面是这篇论文的原貌(截图自原文):
单纯从数学的角度看,反向传播算法并没有什么创新,函数求导的链式法则是微积分的发明人莱布尼兹时代出现的成果。但用于多层神经网络却让这种机器学习算法真正具有了实用价值。
链式法则
在正式介绍神经网络的原理之前,先回顾一下多元函数求导的链式法则。对于如下的多元复合函数:
在这里,x和y是自变量。其中u,v,w是x的函数,u,v是y的函数,而f又是u,v,w的函数。根据链式法则,函数f对x和y的偏导数分别为:
总结起来,函数自变量x的偏导数等于函数对它上一层的复合节点的偏导数(在这里是u,v,w)与这些节点对x的偏导数乘积之和。因此,我们要计算某一个自变量的偏导数,最直接的路径是找到它上一层的复合节点,根据这些节点的偏导数来计算。
神经网络原理简介
在推导算法之前,我们首先简单介绍一下人工神经网络的原理。大脑的神经元通过突触与其他神经元相连接,接收其他神经元送来的信号,经过汇总处理之后产生输出。在人工神经网络中,神经元的作用和这类似。下图是一个神经元的示意图,左侧为输入数据,右侧为输出数据:
这个神经元接受的输入信号为向量(x1,x2,x3,x4,x5),向量(w1,w2,w3,w4,w5)为输入向量的组合权重,b为偏置项,是标量。神经元对输入向量进行加权求和,并加上偏置项,最后经过激活函数变换产生输出:
为表述简洁,我们把公式写成向量和矩阵形式。对每个神经元,它接受的来自前一层神经元的输入为向量x,本节点的权重向量为w,偏置项为b,该神经元的输出值为:
先计算输入向量与权重向量的内积,加上偏置项,再送入一个函数进行变换,得到输出。这个函数称为激活函数,典型的是sigmoid函数。为什么需要激活函数以及什么样的函数可以充当激活函数,在SIGAI之前的公众号文章“理解神经网络的激活函数”中已经进行了介绍。
神经网络一般有多个层。第一层为输入层,对应输入向量,神经元的数量等于特征向量的维数,这个层不对数据进行处理,只是将输入向量送入下一层中进行计算。中间为隐含层,可能有多个。最后是输出层,神经元的数量等于要分类的类别数,输出层的输出值被用来做分类预测。
下面我们来看一个简单神经网络的例子,如下图所示:
这个网络有3层。第一层是输入层,对应的输入向量为x,有3个神经元,写成分量形式为(x1,x2,x3)它不对数据做任何处理,直接原样送入下一层。中间层有4个神经元,接受的输入数据为向量x,输出向量为y,写成分量形式为(y1,y2,y3,y4,y5)。第三个层为输出层,接受的输入数据为向量y,输出向量为z,写成分量形式为(z1,z2)。第一层到第二层的权重矩阵为W(1),第二层到第三层的权重矩阵为W(2)。权重矩阵的每一行为一个权重向量,是上一层所有神经元到本层某一个神经元的连接权重,这里的上标表示层数。
如果激活函数选用sigmoid函数,则第二层神经元的输出值为:
第三层神经元的输出值为:
如果把yi代入上面二式中,可以将输出向量z表示成输出向量x的函数。通过调整权重矩阵和偏置项可以实现不同的函数映射,因此神经网络就是一个复合函数。
需要解决的一个核心问题是一旦神经网络的结构(即神经元层数,每层神经元数量)确定之后,怎样得到权重矩阵和偏置项。这些参数是通过训练得到的,这是本文推导的核心任务。
一个简单的例子
首先以前面的3层神经网络为例,推导损失函数对神经网络所有参数梯度的计算方法。假设训练样本集中有m个样本(xi,zi)。其中x为输入向量,z为标签向量。现在要确定神经网络的映射函数:
什么样的函数能很好的解释这批训练样本?答案是神经网络的预测输出要尽可能的接近样本的标签值,即在训练集上最小化预测误差。如果使用均方误差,则优化的目标为:
其中h(x)和zi都是向量,求和项内部是向量的2范数平方,即各个分量的平方和。上面的误差也称为欧氏距离损失函数,除此之外还可以使用其他损失函数,如交叉熵、对比损失等。
优化目标函数的自变量是各层的权重矩阵和梯度向量,一般情况下无法保证目标函数是凸函数,因此这不是一个凸优化问题,有陷入局部极小值和鞍点的风险(对于这些概念和问题,SIGAI之前的公众号文章“理解梯度下降法”,“理解凸优化”中已经做了详细介绍),这是神经网络之前一直被诟病的一个问题。可以使用梯度下降法进行求解,使用梯度下降法需要计算出损失函数对所有权重矩阵、偏置向量的梯度值,接下来的关键是这些梯度值的计算。在这里我们先将问题简化,只考虑对单个样本的损失函数:
后面如果不加说明,都使用这种单样本的损失函数。如果计算出了对单个样本损失函数的梯度值,对这些梯度值计算均值即可得到整个目标函数的梯度值。
W(1)和b(1)要被代入到网络的后一层中,是复合函数的内层变量,我们先考虑外层的W(2)和b(2)。权重矩阵W(2)是一个2x4的矩阵,它的两个行分别为向量
首先计算损失函数对权重矩阵每个元素的偏导数,将欧氏距离损失函数展开,有:
如果i = 1,即对权重矩阵第一行的元素求导,上式分子中的后半部分对wij来说是常数。根据链式法则有:
如果i = 2,即对矩阵第二行的元素求导,类似的有:
可以统一写成:
可以发现,第一个下标i决定了权重矩阵的第i行和偏置向量的第i个分量,第二个下标j决定了向量y的第j个分量。这可以看成是一个列向量与一个行向量相乘的结果,写成矩阵形式为:
上式中乘法
对偏置项的偏导数为:
如果i = 1,上式分子中的后半部分对b1来说是常数,有:
如果i = 2,类似的有:
这可以统一写成:
写成矩阵形式为:
偏置项的导数由两部分组成,分别是神经网络预测值与真实值之间的误差,激活函数的导数值,与权重矩阵的偏导数相比唯一的区别是少了yT。接下来计算对W(1)和b(1)的偏导数,由于是复合函数的内层,情况更为复杂。W(1)是一个4x3的矩阵,它的4个行向量为
而:
上式分子中的两部分都有y,因此都与W(1)有关。为了表述简洁,我们令:
根据链式法则有:
这里的
后面3个分量相对于求导变量
i = 3和i = 4时的结果以此类推。综合起来有:
同理有:
如果令:
合并得到:
写成矩阵形式为:
最后计算偏置项的偏导数:
类似的我们得到:
合并后得到:
写成矩阵形式为:
至此,我得到了这个简单网络对所有参数的偏导数,接下来我们将这种做法推广到更一般的情况。从上面的结果可以看出一个规律,输出层的权重矩阵和偏置向量梯度计算公式中共用了
完整的算法
现在考虑一般的情况。假设有m个训练样本(xi,yi),其中xi为输入向量,yi为标签向量。训练的目标是最小化样本标签值与神经网络预测值之间的误差,如果使用均方误差,则优化的目标为:
其中W为神经网络所有参数的集合,包括各层的权重和偏置。这个最优化问题是一个不带约束条件的问题,可以用梯度下降法求解。
上面的误差函数定义在整个训练样本集上,梯度下降法每一次迭代利用了所有训练样本,称为批量梯度下降法。如果样本数量很大,每次迭代都用所有样本进计算成本太高。为了解决这个问题,可以采用单样本梯度下降法,我们将上面的损失函数写成对单个样本的损失函数之和:
定义对单个样本(xi,yi)的损失函数为:
如果采用单个样本进行迭代,梯度下降法第t + 1次迭代时参数的更新公式为:
如果要用所有样本进行迭代,根据单个样本的损失函数梯度计算总损失梯度即可,即所有样本梯度的均值。
用梯度下降法求解需要初始化优化变量的值。一般初始化为一个随机数,如用正态分布
到目前为止还有一个关键问题没有解决:目标函数是一个多层的复合函数,因为神经网络中每一层都有权重矩阵和偏置向量,且每一层的输出将会作为下一层的输入。因此,直接计算损失函数对所有权重和偏置的梯度很复杂,需要使用复合函数的求导公式进行递推计算。
几个重要的结论
在进行推导之前,我们首先来看下面几种复合函数的求导。又如下线性映射函数:
其中x是n维向量,W是mxn的矩阵,y是m维向量。
问题1:假设有函数f(y),如果把x看成常数,y看成W的函数,如何根据函数对y的梯度值
对于W的所有元素有:
写成矩阵形式为:
问题2:如果将W看成常数,y将看成x的函数,如何根据
写成矩阵形式为:
这是一个对称的结果,在计算函数映射时用矩阵W乘以向量x得到y,在求梯度时用矩阵W的转置乘以y的梯度得到x的梯度。
问题3:如果有向量到向量的映射:
写成分量形式为:
在这里每个yi只和对应的xi有关,和其他所有
写成矩阵形式为:
即两个向量对应元素相乘,这种乘法在上一节已经介绍。
问题4:接下来我们考虑更复杂的情况,如果有下面的复合函数:
其中g是向量对应元素一对一映射,即:
如果有函数f(y),如何根据
问题5:x是n维向量,y是m维向量,有映射y=g(x),即:
这里的映射方式和上面介绍的不同。对于向量y的每个分量yi,映射函数gi不同,而且yi和向量x的每个分量xj有关。对于函数f(y),如何根据
对于所有元素有:
写成矩阵形式有:
其中
其中向量
即输出向量的每个分量是输入向量的函数。雅克比矩阵定义为输出向量的每个分量对输入向量的每个分量的偏导数构成的矩阵:
这是一个m行n列的矩阵,每一行为一个多元函数的梯度。对于如下向量映射函数:
它的雅克比矩阵为:
前面介绍的几个问题都是这个映射的特例。
完整的算法
根据上面的结论可以方便的推导出神经网络的求导公式。假设神经网络有nl层,第l层神经元个数为Sl。第1层从第l-1层接收的输入向量为x(l-1),本层的权重矩阵为W(l),偏置向量为b(l),输出向量为x(l)。该层的输出可以写成如下矩阵形式:
其中W(l)是slxsl-1的矩阵,u(l)和b(l)是sl维的向量。神经网络一个层实现的变换如下图所示:
如果将神经网络按照各个层展开,最后得到一个深层的复合函数,将其代入欧氏距离损失函数,依然是一个关于各个层的权重矩阵和偏置向量的复合函数:
要计算某一层的权重矩阵和偏置向量的梯度,只能依赖于它紧贴着的外面那一层变量的梯度值,通过一次复合函数求导得到。
根据定义,w(l)和b(l)是目标函数的自变量,u(l)和x(l)可以看成是它们的函数。根据前面的结论,损失函数对权重矩阵的梯度为:
对偏置向量的梯度为:
现在的问题是,梯度
这就是输出层的神经元输出值与期望值之间的误差。这样我们得到输出层权重的梯度为:
等号右边第一个乘法是向量对应元素乘;第二个乘法是矩阵乘,在这里是列向量与行向量的乘积,结果是一个矩阵,尺寸刚好和权重矩阵相同。损失函数对偏置项的梯度为:
下面考虑第二种情况。如果第l层是隐含层,则有:
假设梯度
这是一个递推的关系,通过
为此我们定义误差项为损失函数对临时变量u的梯度:
向量
根据误差项可以方便的计算出对权重和偏置的偏导数。首先计算输出层的误差项,根据他得到权重和偏置项的梯度,这是起点;根据上面的递推公式,逐层向前,利用后一层的误差项计算出本层的误差项,从而得到本层权重和偏置项的梯度。
单个样本的反向传播算法在每次迭代时的流程为:
1.正向传播,利用当前权重和偏置值,计算每一层对输入样本的输出值
2.反向传播,对输出层的每一个节点计算其误差:
3.对于
4.根据误差计算损失函数对权重的梯度值:
对偏置的梯度为:
5.用梯度下降法更新权重和偏置:
实现时需要在正向传播时记住每一层的输入向量x(l-1),本层的激活函数导数值
神经网络的训练算法可以总结为:
复合函数求导+梯度下降法
训练算法有两个版本:批量模式和单样本模式。批量模式每次梯度下降法迭代时对所有样本计算损失函数值,计算出对这些样本的总误差,然后用梯度下降法更新参数;单样本模式是每次对一个样本进行前向传播,计算对该样本的误差,然后更新参数,它可以天然的支持增量学习,即动态的加入新的训练样本进行训练。
在数学中,向量一般是列向量,但在编程语言中,向量一般按行存储,即是行向量,因此实现时计算公式略有不同,需要进行转置。正向传播时的计算公式为:
感兴趣的读者可以阅读各个开源库,对比它们的计算公式。反向传播时的计算公式为:
对权重矩阵的计算公式为:
这些向量都是行向量。
推荐文章
[1] 机器学习-波澜壮阔40年 SIGAI 2018.4.13.
[2] 学好机器学习需要哪些数学知识?SIGAI 2018.4.17.
[3] 人脸识别算法演化史 SIGAI 2018.4.20.
[4] 基于深度学习的目标检测算法综述 SIGAI 2018.4.24.
[5] 卷积神经网络为什么能够称霸计算机视觉领域? SIGAI 2018.4.26.
[6] 用一张图理解SVM的脉络 SIGAI 2018.4.28.
[7] 人脸检测算法综述 SIGAI 2018.5.3.
[8] 理解神经网络的激活函数 SIGAI 2018.5.5.
[9] 深度卷积神经网络演化历史及结构改进脉络-40页长文全面解读 SIGAI 2018.5.8.
[10] 理解梯度下降法 SIGAI 2018.5.11.
[11] 循环神经网络综述—语音识别与自然语言处理的利器 SIGAI 2018.5.15
[12] 理解凸优化 SIGAI 2018.5.18
[13]【实验】理解SVM的核函数和参数 SIGAI 2018.5.22
[14] 【SIGAI综述】行人检测算法 SIGAI 2018.5.25
[15] 机器学习在自动驾驶中的应用—以百度阿波罗平台为例(上) SIGAI 2018.5.29
[16] 理解牛顿法 SIGAI 2018.5.31
[17]【群话题精华】5月集锦—机器学习和深度学习中一些值得思考的问题 SIGAI 2018.6.1
[18] 大话Adaboost算法 SIGAI 2018.6.2
[19] FlowNet到FlowNet2.0:基于卷积神经网络的光流预测算法 SIGAI 2018.6.4[20] 理解主成分分析(PCA) SIGAI 2018.6.6[21] 人体骨骼关键点检测综述 SIGAI 2018.6.8[22] 理解决策树 SIGAI 2018.6.11[23] 用一句话总结常用的机器学习算法 SIGAI 2018.6.13[24] 目标检测算法之YOLO SIGAI 2018.6.15[25] 理解过拟合 SIGAI 2018.6.18[26] 理解计算:从√2到AlphaGo ——第1季 从√2谈起 SIGAI 2018.6.20[27] 场景文本检测——CTPN算法介绍 SIGAI 2018.6.22[28] 卷积神经网络的压缩和加速 SIGAI 2018.6.25[29] k近邻算法 SIGAI 2018.6.27[30] 自然场景文本检测识别技术综述 SIGAI 2018.6.27
[31] 理解计算:从√2到AlphaGo ——第2季 神经计算的历史背景 SIGAI 2018.7.4
[32] 机器学习算法地图 SIGAI2018.7.6
本文为SIGAI原创
如需转载,欢迎发消息到本订号